﻿/**
 * @file audio_opus.cpp
 * Copyright (c) Gaaagaa. All rights reserved.
 * 
 * @author  : Gaaagaa
 * @date    : 2020-03-05
 * @version : 1.0.0.0
 * @brief   : 封装 libopus 的 API，实现 PCM 音频数据的 opus 编解码操作。
 */

#include "audio_opus.h"

#include <opus/opus.h>

/////////////////////////////////////////////////////////////////////////////////

#define XEHANDLE(xhandle)  ((OpusEncoder *)(xhandle))
#define XDHANDLE(xhandle)  ((OpusDecoder *)(xhandle))

////////////////////////////////////////////////////////////////////////////////
// opus_encoder_t

/**********************************************************/
/**
 * @brief 判断 采样率值 是否为 OPUS 支持的采样率。
 */
static inline x_bool_t is_valid_samprate(x_uint32_t xut_samprate)
{
    x_bool_t xbt_valid = X_FALSE;

    switch (xut_samprate)
    {
    case XOPUS_SAMPRATE__8K : xbt_valid = X_TRUE; break;
    case XOPUS_SAMPRATE_12K : xbt_valid = X_TRUE; break;
    case XOPUS_SAMPRATE_16K : xbt_valid = X_TRUE; break;
    case XOPUS_SAMPRATE_24K : xbt_valid = X_TRUE; break;
    case XOPUS_SAMPRATE_48K : xbt_valid = X_TRUE; break;

    default: break;
    }

    return xbt_valid;
}

/**********************************************************/
/**
 * @brief 判断 APP 值类型的有效性。
 */
static inline x_bool_t is_valid_app(x_uint32_t xut_apptype)
{
    x_bool_t xbt_valid = X_FALSE;

    switch (xut_apptype)
    {
    case XOPUS_ENC_APP_VOIP     : xbt_valid = X_TRUE; break;
    case XOPUS_ENC_APP_AUDIO    : xbt_valid = X_TRUE; break;
    case XOPUS_ENC_APP_LOWDELAY : xbt_valid = X_TRUE; break;

    default: break;
    }

    return xbt_valid;
}

/**********************************************************/
/**
 * @brief 在 xopus_enc_config_t 中枚举值所映射的 OPUS application 值。
 */
static inline x_int32_t enc_application(x_uint32_t xut_apptype)
{
    x_int32_t xit_apptype = X_FALSE;

    switch (xut_apptype)
    {
    case XOPUS_ENC_APP_VOIP     : xit_apptype = OPUS_APPLICATION_VOIP               ; break;
    case XOPUS_ENC_APP_AUDIO    : xit_apptype = OPUS_APPLICATION_AUDIO              ; break;
    case XOPUS_ENC_APP_LOWDELAY : xit_apptype = OPUS_APPLICATION_RESTRICTED_LOWDELAY; break;

    default: break;
    }

    return xit_apptype;
}

/**********************************************************/
/**
 * @brief 判断 PCM 值类型的有效性。
 */
static inline x_bool_t is_valid_pcm(x_uint32_t xut_pcmtype)
{
    x_bool_t xbt_valid = X_FALSE;

    switch (xut_pcmtype)
    {
    case XOPUS_PCM_S16 : xbt_valid = X_TRUE; break;
    case XOPUS_PCM_F32 : xbt_valid = X_TRUE; break;

    default: break;
    }

    return xbt_valid;
}

/**********************************************************/
/**
 * @brief 在 xopus_enc_config_t 中枚举值所映射的 OPUS bandwidth 值。
 */
static inline x_int32_t enc_bandwidth(x_uint32_t xut_bandwidth)
{
    x_int32_t xit_bandwidth = OPUS_AUTO;

    switch (xut_bandwidth)
    {
    case XOPUS_ENC_BANDWIDTH_NB  : xit_bandwidth = OPUS_BANDWIDTH_NARROWBAND   ; break;
    case XOPUS_ENC_BANDWIDTH_MB  : xit_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND   ; break;
    case XOPUS_ENC_BANDWIDTH_WB  : xit_bandwidth = OPUS_BANDWIDTH_WIDEBAND     ; break;
    case XOPUS_ENC_BANDWIDTH_SWB : xit_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; break;
    case XOPUS_ENC_BANDWIDTH_FB  : xit_bandwidth = OPUS_BANDWIDTH_FULLBAND     ; break;

    default: break;
    }

    return xit_bandwidth;
}

/**********************************************************/
/**
 * @brief 在 xopus_enc_config_t 中枚举值所映射的 OPUS LSB DEPTH 值。
 */
static inline x_int32_t enc_lsb_depth(x_uint32_t xut_epcmtype)
{
    x_int32_t xit_lsb_depth = 0;

    switch (xut_epcmtype)
    {
    case XOPUS_ENC_INPUT_PCM_S16 : xit_lsb_depth = 16; break;
    case XOPUS_ENC_INPUT_PCM_F32 : xit_lsb_depth = 24; break;

    default: break;
    }

    return xit_lsb_depth;
}

/**********************************************************/
/**
 * @brief 在 xopus_enc_config_t 中枚举值所映射的 OPUS 帧持续时间内置常量。
 */
static inline x_int32_t enc_fduration(x_uint32_t xut_fms)
{
    x_int32_t xit_fduration = OPUS_FRAMESIZE_20_MS;

    switch (xut_fms)
    {
    case XOPUS_ENC_FRAMEMS_2P5 : xit_fduration = OPUS_FRAMESIZE_2_5_MS; break;
    case XOPUS_ENC_FRAMEMS_5   : xit_fduration = OPUS_FRAMESIZE_5_MS  ; break;
    case XOPUS_ENC_FRAMEMS_10  : xit_fduration = OPUS_FRAMESIZE_10_MS ; break;
    case XOPUS_ENC_FRAMEMS_20  : xit_fduration = OPUS_FRAMESIZE_20_MS ; break;
    case XOPUS_ENC_FRAMEMS_40  : xit_fduration = OPUS_FRAMESIZE_40_MS ; break;
    case XOPUS_ENC_FRAMEMS_60  : xit_fduration = OPUS_FRAMESIZE_60_MS ; break;
    case XOPUS_ENC_FRAMEMS_80  : xit_fduration = OPUS_FRAMESIZE_80_MS ; break;
    case XOPUS_ENC_FRAMEMS_100 : xit_fduration = OPUS_FRAMESIZE_100_MS; break;
    case XOPUS_ENC_FRAMEMS_120 : xit_fduration = OPUS_FRAMESIZE_120_MS; break;

    default: break;
    }

    return xit_fduration;
}

/**********************************************************/
/**
 * @brief 按设定的帧输出间隔时间要求，计算编码时每帧的采样数量。
 */
static inline x_int32_t enc_fsamples(x_uint32_t xut_fms, x_uint32_t xut_samprate)
{
    x_int32_t xit_fsamples = 0;

    switch (xut_fms)
    {
    case XOPUS_ENC_FRAMEMS_2P5 : xit_fsamples = 1 * xut_samprate / 400; break;
    case XOPUS_ENC_FRAMEMS_5   : xit_fsamples = 1 * xut_samprate / 200; break;
    case XOPUS_ENC_FRAMEMS_10  : xit_fsamples = 1 * xut_samprate / 100; break;
    case XOPUS_ENC_FRAMEMS_20  : xit_fsamples = 1 * xut_samprate /  50; break;
    case XOPUS_ENC_FRAMEMS_40  : xit_fsamples = 1 * xut_samprate /  25; break;
    case XOPUS_ENC_FRAMEMS_60  : xit_fsamples = 3 * xut_samprate /  50; break;
    case XOPUS_ENC_FRAMEMS_80  : xit_fsamples = 4 * xut_samprate /  50; break;
    case XOPUS_ENC_FRAMEMS_100 : xit_fsamples = 5 * xut_samprate /  50; break;
    case XOPUS_ENC_FRAMEMS_120 : xit_fsamples = 6 * xut_samprate /  50; break;

    default: xit_fsamples = xut_samprate / 50; break;
    }

    return xit_fsamples;
}

/**********************************************************/
/**
 * @brief 在 xopus_enc_config_t 中枚举值所映射的 OPUS complexity 值。
 */
static inline x_int32_t enc_complexity(x_uint32_t xut_complexity)
{
    x_int32_t xit_complexity = 0x0A;

    switch (xut_complexity)
    {
    case XOPUS_ENC_COMPLEXITY_0 : xit_complexity = 0x00; break;
    case XOPUS_ENC_COMPLEXITY_1 : xit_complexity = 0x01; break;
    case XOPUS_ENC_COMPLEXITY_2 : xit_complexity = 0x02; break;
    case XOPUS_ENC_COMPLEXITY_3 : xit_complexity = 0x03; break;
    case XOPUS_ENC_COMPLEXITY_4 : xit_complexity = 0x04; break;
    case XOPUS_ENC_COMPLEXITY_5 : xit_complexity = 0x05; break;
    case XOPUS_ENC_COMPLEXITY_6 : xit_complexity = 0x06; break;
    case XOPUS_ENC_COMPLEXITY_7 : xit_complexity = 0x07; break;
    case XOPUS_ENC_COMPLEXITY_8 : xit_complexity = 0x08; break;
    case XOPUS_ENC_COMPLEXITY_9 : xit_complexity = 0x09; break;
    case XOPUS_ENC_COMPLEXITY_A : xit_complexity = 0x0A; break;

    default: break;
    }

    return xit_complexity;
}

//====================================================================

// 
// opus_encoder_t : constructor/destuctor
// 

opus_encoder_t::opus_encoder_t(void)
    : m_xht_encoder(X_NULL)
    , m_xut_epcmtype(0)
    , m_xut_channels(0)
    , m_xut_samprate(0)
    , m_xut_fsamples(0)
{

}

opus_encoder_t::~opus_encoder_t(void)
{
    close();
}

//====================================================================

// 
// opus_encoder_t : public interfaces
// 

/**********************************************************/
/**
 * @brief 打开编码器对象。
 * 
 * @param [in ] xut_channels : 通道数量（仅支持 1 或 2）。
 * @param [in ] xut_samprate : 采样率（仅支持 xopus_samplerate_t 列举的枚举值）。
 * @param [in ] xut_apptype  : 应用类型（参看 xopus_app_t）。
 * @param [in ] xut_config   : 编码操作的配置选项（使用 xopus_enc_config_t 的组合值）。
 * @param [in ] xut_bitrate  : 编码输出的位速。
 * 
 * @return x_errno_t : 错误码。
 * @retval X_ERR_OK, 操作成功。
 * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
 * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
 */
x_errno_t opus_encoder_t::open(
                x_uint16_t xut_channels,
                x_uint32_t xut_samprate,
                x_uint32_t xut_config  /* = XOPUS_ENC_DEFAULT */,
                x_uint32_t xut_bitrate /* = 0 */)
{
    x_errno_t xerr_no = X_ERR_UNKNOW;
    x_int32_t xit_err = X_ERR_UNKNOW;

    OpusEncoder * xencoder = X_NULL;

    do
    {
        //======================================
        // 参数的有效判断

        if ((1 != xut_channels) && (2 != xut_channels))
        {
            xerr_no = XERR_MAKE(X_ERR_INVALID_CHANNELS, 0);
            break;
        }

        if (!is_valid_samprate(xut_samprate))
        {
            xerr_no = XERR_MAKE(X_ERR_INVALID_SAMPRATE, 0);
            break;
        }

        if (!is_valid_app(XOPUS_ENC_GET_APP(xut_config)))
        {
            xerr_no = XERR_MAKE(X_ERR_INVALID_APPTYPE, 0);
            break;
        }

        if (!is_valid_pcm(XOPUS_ENC_GET_PCM(xut_config)))
        {
            xerr_no = XERR_MAKE(X_ERR_INVALID_PCMTYPE, 0);
            break;
        }

        if (is_open())
        {
            close();
        }

        //======================================
        // 创建 OpusEncoder 对象

        xencoder = opus_encoder_create(
                        xut_samprate,
                        xut_channels,
                        enc_application(XOPUS_ENC_GET_APP(xut_config)),
                        &xit_err);
        if (OPUS_OK != xit_err)
        {
            xerr_no = XERR_MAKE(X_ERR_CREATE_ENCODER, xit_err);
            break;
        }

        //======================================
        // 配置解码器工作参数

        x_int32_t xit_fsamples    = 0;
        x_int32_t xit_bitrate     = (0 == xut_bitrate) ? OPUS_AUTO : (x_int32_t)xut_bitrate;
        x_int32_t xit_bandwidth   = enc_bandwidth(XOPUS_ENC_GET_BW(xut_config));
        x_int32_t xit_use_vbr     = !XOPUS_ENC_BITMODE(xut_config, XOPUS_ENC_ENABLE_CBR);
        x_int32_t xit_use_cvbr    = XOPUS_ENC_BITMODE(xut_config, XOPUS_ENC_ENABLE_CVBR);
        x_int32_t xit_complexity  = enc_complexity(XOPUS_ENC_GET_CP(xut_config));
        x_int32_t xit_inbandfec   = XOPUS_ENC_BITMODE(xut_config, XOPUS_ENC_ENABLE_INBANDFEC);
        x_int32_t xit_force_mono  = XOPUS_ENC_BITMODE(xut_config, XOPUS_ENC_FORCE_MONO) ? 1 : OPUS_AUTO;
        x_int32_t xit_use_dtx     = XOPUS_ENC_BITMODE(xut_config, XOPUS_ENC_ENABLE_DTX);
        x_int32_t xit_losspercent = XOPUS_ENC_GET_LP(xut_config);
        x_int32_t xit_lsb_depth   = enc_lsb_depth(XOPUS_ENC_GET_PCM(xut_config));

        xit_losspercent = ((xit_losspercent > 100) ? 100 : xit_losspercent);

#define X_ENC_CTL(xexp, xerr)                       \
        xit_err = opus_encoder_ctl(xencoder, xexp); \
        if (OPUS_OK != xit_err)                     \
        {                                           \
            xerr_no = XERR_MAKE(xerr, xit_err);    \
            break;                                  \
        }

        X_ENC_CTL(OPUS_SET_BITRATE(xit_bitrate)             , X_ERR_ECTL_SET_BITRATE   )
        X_ENC_CTL(OPUS_SET_BANDWIDTH(xit_bandwidth)         , X_ERR_ECTL_SET_BANDWIDTH )
        X_ENC_CTL(OPUS_SET_VBR(xit_use_vbr)                 , X_ERR_ECTL_SET_CBR       )
        X_ENC_CTL(OPUS_SET_VBR_CONSTRAINT(xit_use_cvbr)     , X_ERR_ECTL_SET_CVBR      )
        X_ENC_CTL(OPUS_SET_COMPLEXITY(xit_complexity)       , X_ERR_ECTL_SET_COMPLEXITY)
        X_ENC_CTL(OPUS_SET_INBAND_FEC(xit_inbandfec)        , X_ERR_ECTL_SET_INBAND_FEC)
        X_ENC_CTL(OPUS_SET_FORCE_CHANNELS(xit_force_mono)   , X_ERR_ECTL_SET_FORCE_MONO)
        X_ENC_CTL(OPUS_SET_DTX(xit_use_dtx)                 , X_ERR_ECTL_SET_DTX       )
        X_ENC_CTL(OPUS_SET_PACKET_LOSS_PERC(xit_losspercent), X_ERR_ECTL_SET_LOSS_PERC )
        X_ENC_CTL(OPUS_SET_LSB_DEPTH(xit_lsb_depth)         , X_ERR_ECTL_SET_LSB_DEPTH )

        if (XOPUS_ENC_BITMODE(xut_config, XOPUS_ENC_DELAYED_DECISION))
        {
            x_int32_t xit_fduration = enc_fduration(XOPUS_ENC_GET_FMS(xut_config));
            X_ENC_CTL(OPUS_SET_EXPERT_FRAME_DURATION(xit_fduration), X_ERR_ECTL_SET_FDURATION)
            xit_fsamples = 2 * XOPUS_SAMPRATE_48K;
        }
        else
        {
            X_ENC_CTL(OPUS_SET_EXPERT_FRAME_DURATION(OPUS_FRAMESIZE_ARG), X_ERR_ECTL_SET_FDURATION)
            xit_fsamples = enc_fsamples(XOPUS_ENC_GET_FMS(xut_config), xut_samprate);
        }

#undef X_ENC_CTL

        //======================================

        m_xht_encoder  = (x_handle_t)xencoder;
        m_xut_epcmtype = XOPUS_ENC_GET_PCM(xut_config);
        m_xut_channels = xut_channels;
        m_xut_samprate = xut_samprate;
        m_xut_fsamples = xit_fsamples;

        xencoder = X_NULL;

        //======================================
        xerr_no = X_ERR_OK;
    } while (0);

    if (X_NULL != xencoder)
    {
        opus_encoder_destroy(xencoder);
        xencoder = X_NULL;
    }

    return xerr_no;
}

/**********************************************************/
/**
 * @brief 关闭编码器对象。
 */
x_void_t opus_encoder_t::close(void)
{
    if (X_NULL != m_xht_encoder)
    {
        opus_encoder_destroy(XEHANDLE(m_xht_encoder));
        m_xht_encoder = X_NULL;
    }

    m_xut_epcmtype = 0;
    m_xut_channels = 0;
    m_xut_samprate = 0;
    m_xut_fsamples = 0;
}

/**********************************************************/
/**
 * @brief 每次编码输入的每帧 PCM 音频所需字节数。
 */
x_uint32_t opus_encoder_t::frame_len(void) const
{
    if (XOPUS_PCM_S16 == m_xut_epcmtype)
        return (sizeof(x_int16_t) * m_xut_channels * m_xut_fsamples);
    return (sizeof(x_float_t) * m_xut_channels * m_xut_fsamples);
}

/**********************************************************/
/**
 * @brief 执行 PCM-S16/PCM-F32 音频数据编码操作。
 * @note 
 * 输入的音频帧 xbuf_vpcm 格式必须与编码器使用的类型一致，
 * 即可以是 S16（16位有符号整型）或 F32（32位浮点型），
 * 缓存的有效数据字节数为 frame_len()，若输入时不足，请用 0 填充。
 * 
 * @param [out   ] xbuf_opus : 输出编码后的音频数据所使用的缓存。
 * @param [in,out] xut_osize : 入参，xbuf_opus 缓存大小（建议 >= 1024）；
 *                             回参，操作成功时输出编码后的有效数据大小。
 * @param [in    ] xbuf_vpcm : 输入的 PCM 音频帧数据。
 * @param [in,out] xut_fsize : 入参，xbuf_vpcm 缓存输入的有效数据字节数（必须 == frame_len()）；
 *                             回参，操作成功时输出编码后的有效数据字节数。
 * 
 * @return x_errno_t : 错误码。
 * @retval X_ERR_OK, 操作成功。
 * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
 * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
 */
x_errno_t opus_encoder_t::encode(
                xopusbuf_t   xbuf_opus,
                x_uint32_t & xut_osize,
                cvpcmbuf_t   xbuf_vpcm,
                x_uint32_t & xut_fsize)
{
    x_errno_t xerr_no = X_ERR_UNKNOW;

    do
    {
        //======================================

        if (!is_open())
        {
            xerr_no = XERR_MAKE(X_ERR_ENCODE_UNOPEN, 0);
            break;
        }

        if ((X_NULL == xbuf_opus) || (xut_osize < sizeof(x_int16_t)) ||
            (X_NULL == xbuf_vpcm) || (xut_fsize != frame_len()))
        {
            xerr_no = XERR_MAKE(X_ERR_ENCODE_ARGS, 0);
            break;
        }

        //======================================

        x_int32_t xit_sizeof = sizeof(x_int16_t);
        x_int32_t xit_obytes = 0;
        x_int32_t xit_osamps = 0;

        if (XOPUS_ENC_INPUT_PCM_S16 == m_xut_epcmtype)
        {
            xit_obytes = opus_encode(
                                XEHANDLE(m_xht_encoder),
                                (const x_int16_t *)xbuf_vpcm,
                                m_xut_fsamples,
                                xbuf_opus,
                                xut_osize);
            if (xit_obytes < 0)
            {
                xerr_no = XERR_MAKE(X_ERR_ENCODE_ENCS16, xit_obytes);
                break;
            }
        }
        else
        {
            xit_obytes = opus_encode_float(
                                XEHANDLE(m_xht_encoder),
                                (const x_float_t *)xbuf_vpcm,
                                m_xut_fsamples,
                                xbuf_opus,
                                xut_osize);
            if (xit_obytes < 0)
            {
                xerr_no = XERR_MAKE(X_ERR_ENCODE_ENCF32, xit_obytes);
                break;
            }

            xit_sizeof = sizeof(x_float_t);
        }

        //======================================

        if (xit_obytes > 0)
        {
            xit_osamps = opus_packet_get_nb_samples(
                            xbuf_opus, xit_obytes, (x_int32_t)m_xut_samprate);
            if (xit_osamps < 0)
            {
                xerr_no = XERR_MAKE(X_ERR_ENCODE_PACKET, xit_osamps);
                break;
            }
        }

        xut_osize = xit_obytes;
        xut_fsize = xit_sizeof * m_xut_channels * xit_osamps;

        //======================================
        xerr_no = X_ERR_OK;
    } while (0);

    return xerr_no;
}

////////////////////////////////////////////////////////////////////////////////
// opus_decoder_t

//====================================================================

// 
// opus_decoder_t : constructor/destuctor
// 

opus_decoder_t::opus_decoder_t(void)
    : m_xht_decoder(X_NULL)
    , m_xut_epcmtype(0)
    , m_xut_channels(0)
    , m_xut_samprate(0)
{

}

opus_decoder_t::~opus_decoder_t(void)
{
    close();
}

//====================================================================

// 
// opus_decoder_t : public interfaces
// 

/**********************************************************/
/**
 * @brief 打开解码器对象。
 * 
 * @param [in ] xut_epcmtype : 解码操作的 PCM 音频格式（PCM-S16/PCM-F32）。
 * @param [in ] xut_channels : 解码操作的通道数。
 * @param [in ] xut_samprate : 解码操作的音频采样率。
 * 
 * @return x_errno_t : 错误码。
 * @retval X_ERR_OK, 操作成功。
 * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
 * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
 */
x_errno_t opus_decoder_t::open(
                x_uint16_t xut_epcmtype,
                x_uint16_t xut_channels,
                x_uint32_t xut_samprate)
{
    x_errno_t xerr_no = X_ERR_UNKNOW;
    x_int32_t xit_err = X_ERR_UNKNOW;

    OpusDecoder * xdecoder = X_NULL;

    do
    {
        //======================================

        if (!is_valid_pcm(xut_epcmtype))
        {
            xerr_no = XERR_MAKE(X_ERR_INVALID_PCMTYPE, 0);
            break;
        }

        if ((1 != xut_channels) && (2 != xut_channels))
        {
            xerr_no = XERR_MAKE(X_ERR_INVALID_CHANNELS, 0);
            break;
        }

        if (!is_valid_samprate(xut_samprate))
        {
            xerr_no = XERR_MAKE(X_ERR_INVALID_SAMPRATE, 0);
            break;
        }

        if (is_open())
        {
            close();
        }

        //======================================

        xdecoder = opus_decoder_create(xut_samprate, xut_channels, &xit_err);
        if (OPUS_OK != xit_err)
        {
            xerr_no = XERR_MAKE(X_ERR_CREATE_DECODER, xit_err);
            break;
        }

        //======================================

        m_xht_decoder  = (x_handle_t)xdecoder;
        m_xut_epcmtype = xut_epcmtype;
        m_xut_channels = xut_channels;
        m_xut_samprate = xut_samprate;

        xdecoder = X_NULL;

        //======================================
        xerr_no = X_ERR_OK;
    } while (0);

    return xerr_no;
}

/**********************************************************/
/**
 * @brief 关闭解码器对象。
 */
x_void_t opus_decoder_t::close(void)
{
    if (X_NULL != m_xht_decoder)
    {
        opus_decoder_destroy(XDHANDLE(m_xht_decoder));
        m_xht_decoder = X_NULL;
    }

    m_xut_epcmtype = 0;
    m_xut_channels = 0;
    m_xut_samprate = 0;
}

/**********************************************************/
/**
 * @brief 执行解码操作。
 * 
 * @param [out   ] xbuf_vpcm : 输出解码后的 PCM-S16/PCM-F32 音频数据所使用的缓存。
 * @param [in,out] xut_fsize : 入参，xbuf_pcm 缓存大小（按字节计数）；
 *                             回参，xbuf_pcm 中有效数据长度（按字节计数）。
 * @param [in    ] xbuf_opus : 输入待解码的 OPUS 音频数据的缓存。
 * @param [in    ] xut_osize : xbuf_opus 缓存中有效数据长度（按字节计数）。
 * 
 * @return x_errno_t : 错误码。
 * @retval X_ERR_OK, 操作成功。
 * @retval XERR_HINO(xerr_no)，参看 xerrno_table_t 相关枚举值。
 * @retval XERR_LONO(xerr_no)，所引用的模块返回的错误码值。
 */
x_errno_t opus_decoder_t::decode(
                    xvpcmbuf_t   xbuf_vpcm,
                    x_uint32_t & xut_fsize,
                    copusbuf_t   xbuf_opus,
                    x_uint32_t   xut_osize)
{
    x_errno_t xerr_no = X_ERR_UNKNOW;

    do
    {
        //======================================

        if (!is_open())
        {
            xerr_no = XERR_MAKE(X_ERR_DECODE_UNOPEN, 0);
            break;
        }

        if ((X_NULL == xbuf_vpcm) ||
            (xut_fsize < (sizeof(x_float_t) * m_xut_channels)))
        {
            xerr_no = XERR_MAKE(X_ERR_DECODE_ARGS, 0);
            break;
        }

        //======================================

        x_int32_t xit_sizeof = sizeof(x_int16_t);
        x_int32_t xit_osamps = 0;

        if (XOPUS_PCM_S16 == m_xut_epcmtype)
        {
            xit_osamps =
                opus_decode(
                    XDHANDLE(m_xht_decoder),
                    xbuf_opus,
                    xut_osize,
                    (x_int16_t *)xbuf_vpcm,
                    (x_int32_t)(xut_fsize / (xit_sizeof * m_xut_channels)),
                    0);
            if (xit_osamps < 0)
            {
                xerr_no = XERR_MAKE(X_ERR_DECODE_DECS16, xit_osamps);
                break;
            }
        }
        else
        {
            xit_osamps =
                opus_decode_float(
                    XDHANDLE(m_xht_decoder),
                    xbuf_opus,
                    xut_osize,
                    (x_float_t *)xbuf_vpcm,
                    (x_int32_t)(xut_fsize / (xit_sizeof * m_xut_channels)),
                    0);
            if (xit_osamps < 0)
            {
                xerr_no = XERR_MAKE(X_ERR_DECODE_DECF32, xit_osamps);
                break;
            }
        }

        xut_fsize = xit_sizeof * m_xut_channels * xit_osamps;

        //======================================
        xerr_no = X_ERR_OK;
    } while (0);

    return xerr_no;
}

